#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <linux/netlink.h>

#define MSG_LEN 256
#define NETLINK_SYSREC    (31)  
#define MAX_PAYLOAD     (1024)  

typedef struct _user_msg_info {
	struct nlmsghdr hdr;
	char msg[MSG_LEN];
}user_msg_info;

static int netlink_sendmsg(int sfd, unsigned char *message, int *len,
		unsigned int pid, unsigned int group)
{
	struct nlmsghdr *nlh = NULL;
	struct sockaddr_nl dst_addr;
	struct iovec iov;  //数据缓冲区,包含头
	struct msghdr msg;	
	
	if (!message)
		return -1;
	//create message
	//填充头
	nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
	if (!nlh) {
		perror("malloc");
		return -2;
	}
	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
	nlh->nlmsg_pid = getpid();
	nlh->nlmsg_flags = 0;
	memcpy(NLMSG_DATA(nlh), message, *len);
	
	iov.iov_base = (void *)nlh;
	iov.iov_len = nlh->nlmsg_len;
	memset(&dst_addr, 0, sizeof(struct sockaddr_nl));
	dst_addr.nl_family = AF_NETLINK;
	dst_addr.nl_pid = pid;
	dst_addr.nl_groups = group;
	
	//填充消息数据
	memset(&msg, 0, sizeof(struct msghdr));
	msg.msg_name = (void *)&dst_addr; //// 指向目标地址的指针
	msg.msg_namelen = sizeof(struct sockaddr_nl);
	msg.msg_iov = &iov; //指向数据缓冲区的指针
	msg.msg_iovlen = 1;// 数据缓冲区的长度

	//send message
	if (sendmsg(sfd, &msg, 0) < 0) {
		printf("send error!\n");  
                free(nlh);  
                return -3; 
	} else 
		printf("send success, len:%d\n", *len);

	free(nlh);  
	return 0;
}

static int netlink_recvmsg(int sfd, unsigned char *message, int *len)
{
	struct nlmsghdr *nlh = NULL;
	struct sockaddr_nl src_addr;
	struct iovec iov;  //数据缓冲区,包含头1
	struct msghdr msg;
	
	if (!message || !len)
		return -1;

	//create message
	nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
	if (!nlh) {
		perror("malloc");
		return -2;
	}

	 iov.iov_base = (void *)nlh;  
        iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);  
        memset(&src_addr, 0, sizeof(struct sockaddr_nl));  
        memset(&msg, 0, sizeof(struct msghdr));  
        msg.msg_name = (void *)&src_addr;  
        msg.msg_namelen = sizeof(struct sockaddr_nl);  
        msg.msg_iov = &iov;  
        msg.msg_iovlen = 1;  
			
	if (recvmsg(sfd, &msg, 0) < 0) {
		printf("recvmsg error!\n");
                return -3;
	}

	*len = nlh->nlmsg_len - NLMSG_SPACE(0);
        memcpy(message, (unsigned char *)NLMSG_DATA(nlh), *len);

	free(nlh);
	return 0;
}

int main(int ac, char *av[]) {

	int sfd;
	int ret;
	int len;
	struct sockaddr_nl addr;
	user_msg_info msg;
	char buf[MSG_LEN];
	char ubuf[MSG_LEN];
		

	//创建netlink socket
	sfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SYSREC);
	if (sfd == -1) {
		perror("create socket error\n");
		return -1;
	}

	//netlink bind
	memset(&addr, 0, sizeof(struct sockaddr_nl));
	addr.nl_family = AF_NETLINK;
	addr.nl_pid = getpid();
	addr.nl_groups = 0;
	ret = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));	
	if (ret < 0) {
		perror("bind socket error\n");
		close(sfd);
		exit(EXIT_FAILURE);
	}
	/*向内核发送数据*/
	strcpy(ubuf, "system handshake kernel");
	len = sizeof(ubuf);
	netlink_sendmsg(sfd, ubuf, &len, 0, 0);
	//len = strlen(av[1]+1);
	//netlink_sendmsg(sfd, av[1], &len, 0, 0);
	
	/*接收内核发过来的数据*/
	//ret = netlink_recvmsg(sfd, buf, &len);
	//if (ret == 0)
	//	printf("recv:%s len:%d\n", buf, len);
	return 0;
}
